package com.atguigu.gmall.product.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.cache.GmallCache;
import com.atguigu.gmall.model.product.*;
import com.atguigu.gmall.product.mapper.*;
import com.atguigu.gmall.product.service.api.ManagerService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: 封捷
 * @create-date: 2022/8/19 10:15
 */
@Service
public class ManagerServiceImpl implements ManagerService {

    @Autowired
    private BaseAttrInfoMapper baseAttrInfoMapper;

    @Autowired
    private BaseCategory1Mapper baseCategory1Mapper;

    @Autowired
    private BaseCategory2Mapper baseCategory2Mapper;

    @Autowired
    private BaseCategory3Mapper baseCategory3Mapper;

    @Autowired
    private BaseAttrValueMapper baseAttrValueMapper;

    @Autowired
    private SpuInfoMapper spuInfoMapper;

    @Autowired
    private BaseSaleAttrMapper baseSaleAttrMapper;

    @Autowired
    private SpuImageMapper spuImageMapper;

    @Autowired
    private SpuSaleAttrMapper spuSaleAttrMapper;

    @Autowired
    private SpuSaleAttrValueMapper spuSaleAttrValueMapper;

    @Autowired
    private SkuInfoMapper skuInfoMapper;

    @Autowired
    private SkuImageMapper skuImageMapper;

    @Autowired
    private SkuAttrValueMapper skuAttrValueMapper;

    @Autowired
    private SkuSaleAttrValueMapper skuSaleAttrValueMapper;

    @Autowired
    private BaseCategoryViewMapper baseCategoryViewMapper;

    @Override
    public List<BaseCategory1> getCategory1List() {

        // 没有查询条件，QueryWrapper 使用 null 值
        return baseCategory1Mapper.selectList(null);
    }

    @Override
    public List<BaseCategory2> getCategory2List(Integer category1Id) {
        return baseCategory2Mapper
                .selectList(
                        // 封装查询条件：where category1_id=#{category1Id}
                        new QueryWrapper<BaseCategory2>().eq("category1_id", category1Id));
    }

    @Override
    public List<BaseCategory3> getCategory3List(Integer category2Id) {
        return baseCategory3Mapper
                .selectList(
                        new QueryWrapper<BaseCategory3>().eq("category2_id", category2Id));
    }

    @Override
    public List<BaseAttrInfo> getBaseAttrInfo(Long category1Id, Long category2Id, Long category3Id) {
        return baseAttrInfoMapper
                .selectBaseAttrInfoList(
                        category1Id,
                        category2Id,
                        category3Id);
    }

    @Override
    // 加上事务注解
    @Transactional
    public void saveBaseAttrInfo(BaseAttrInfo baseAttrInfo) {

        // 第一部分：操作平台属性数据
        // 尝试获取平台属性 id
        Long baseAttrInfoId = baseAttrInfo.getId();

        // 判断平台属性 id 是否有值
        if (baseAttrInfoId == null) {
            // 如果没有值，说明要执行保存操作
            baseAttrInfoMapper.insert(baseAttrInfo);

            // 插入操作成功之后，会产生自增主键值，后面需要用到
            // 所以复制给 baseAttrInfoId 变量
            baseAttrInfoId = baseAttrInfo.getId();
        } else {
            // 如果有值，说明要执行更新操作
            baseAttrInfoMapper.updateById(baseAttrInfo);

            // 第二部分：操作平台属性值集合数据
            // 删除旧数据
            baseAttrValueMapper
                    .delete(
                            new QueryWrapper<BaseAttrValue>()
                                    .eq("attr_id", baseAttrInfoId));
        }

        // 获取平台属性值集合
        List<BaseAttrValue> attrValueList = baseAttrInfo.getAttrValueList();

        // 执行批量保存操作
        baseAttrValueMapper.batchInsert(baseAttrInfoId, attrValueList);

    }

    @Override
    public List<BaseAttrValue> getAttrValueList(Long attrId) {
        return baseAttrValueMapper
                .selectList(
                        new QueryWrapper<BaseAttrValue>()
                                .eq("attr_id", attrId));
    }

    @Override
    public IPage<SpuInfo> getSpuInfoPage(Long page, Long limit, Long category3Id) {

        // 按照 MybatisPlus 要求创建 Page 对象
        Page<SpuInfo> spuInfoPage = new Page<>(page, limit);

        // 根据分页信息执行查询
        return spuInfoMapper
                .selectPage(
                        spuInfoPage,
                        new QueryWrapper<SpuInfo>()
                                .eq("category3_id", category3Id));

    }

    @Override
    public List<BaseSaleAttr> getBaseSaleAttrList() {
        return baseSaleAttrMapper.selectList(null);
    }

    @Override
    @Transactional
    public void saveSpuInfo(SpuInfo spuInfo) {

        // 1、保存 SpuInfo 对象
        spuInfoMapper.insert(spuInfo);

        // 2、获取 spuId 值
        Long spuId = spuInfo.getId();

        // 3、批量保存 SPU 图片
        spuImageMapper.batchInsert(spuId, spuInfo.getSpuImageList());

        // 4、批量保存销售属性和销售属性值
        // [1]获取销售属性数据集合
        List<SpuSaleAttr> spuSaleAttrList = spuInfo.getSpuSaleAttrList();

        // [2]遍历销售属性数据集合
        for (SpuSaleAttr spuSaleAttr : spuSaleAttrList) {

            // [3]给销售属性对象设置 spuId
            spuSaleAttr.setSpuId(spuId);

            // [4]保存销售属性数据本身
            spuSaleAttrMapper.insert(spuSaleAttr);

            // [5]获取销售属性值集合数据
            List<SpuSaleAttrValue> spuSaleAttrValueList = spuSaleAttr.getSpuSaleAttrValueList();

            // [6]获取销售属性名
            String saleAttrName = spuSaleAttr.getSaleAttrName();

            // [7]对销售属性值执行批量保存
            spuSaleAttrValueMapper.batchInsert(spuId, spuSaleAttrValueList, saleAttrName);

        }

    }

    @Override
    public List<SpuImage> getSpuImageList(Long spuId) {
        return spuImageMapper.selectList(
                new QueryWrapper<SpuImage>()
                        .eq("spu_id", spuId));
    }

    @Override
    public List<SpuSaleAttr> getSpuSaleAttrList(Long spuId) {
        return spuSaleAttrMapper.selectSpuSaleAttrList(spuId);
    }

    @Override
    @Transactional
    public void saveSkuInfo(SkuInfo skuInfo) {

        // ※附加功能：skuInfo 对象默认上架
        skuInfo.setIsSale(1);

        // 1、保存 SKU 信息
        skuInfoMapper.insert(skuInfo);

        // 2、获取 SkuInfo 保存后自增的主键
        Long skuInfoId = skuInfo.getId();

        // 3、保存 SkuImageList
        skuImageMapper.batchInsert(
                skuInfoId,
                skuInfo.getSkuImageList());

        // 4、保存 skuAttrValueList
        skuAttrValueMapper.batchInsert(
                skuInfoId,
                skuInfo.getSkuAttrValueList());

        // 5、保存 skuSaleAttrValueList
        skuSaleAttrValueMapper.batchInsert(
                skuInfoId,
                skuInfo.getSpuId(),
                skuInfo.getSkuSaleAttrValueList());

    }

    @Override
    public IPage<SkuInfo> getSkuInfoPage(Long pageNum, Long pageSize) {

        return skuInfoMapper
                .selectPage(new Page<>(pageNum, pageSize),
                        new QueryWrapper<SkuInfo>()
                                .orderByDesc("id"));
    }

    @Override
    public void updateSkuSaleStatus(Long skuId, int isSale) {

        SkuInfo skuInfo = new SkuInfo();

        skuInfo.setId(skuId);

        skuInfo.setIsSale(isSale);

        skuInfoMapper.updateById(skuInfo);
    }

    @Override
    // 去查询数据库的核心方法
    @GmallCache(prefix = "skuInfo")
    public SkuInfo getSkuInfoById(Long skuId) {

        // 先查询 SkuInfo 对象本身（基本信息）
        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);

        if (skuInfo == null) {
            // ※如果 SkuInfo 对象没有查询到，那么当前方法也返回空值
            return null;
        }

        // 根据 skuId 查询对应的图片信息
        List<SkuImage> skuImageList =
                skuImageMapper
                        .selectList(
                                new QueryWrapper<SkuImage>()
                                        .eq("sku_id", skuId));

        // 装配到 SkuInfo 对象中
        skuInfo.setSkuImageList(skuImageList);

        return skuInfo;
    }

    @Override
    @GmallCache(prefix = "categoryView")
    public BaseCategoryView getCategoryViewBy3Id(Long category3Id) {

        // 这里就看出把三级分类 id 作为视图的主键的方便之处了
        return baseCategoryViewMapper.selectById(category3Id);
    }

    @Override
    public BigDecimal getSkuPriceById(Long skuId) {

        return skuInfoMapper.selectPriceById(skuId);
    }

    @Override
    @GmallCache(prefix = "spu:sale:attr:with:check")
    public List<SpuSaleAttr> getSpuSaleAttrAndValueWithCheck(Long skuId, Long spuId) {
        return spuSaleAttrMapper.selectSpuSaleAttrAndValueWithCheck(skuId, spuId);
    }

    @Override
    @GmallCache(prefix = "map:from:sale:value:to:skuId")
    public Map<String, Object> getSaleAttrValuesBySpu(Long spuId) {

        // 先从数据库查询出来原始状态的数据
        // 每一条查询结果对应一个 Map
        List<Map<String, Object>> originalDataList =
                skuSaleAttrValueMapper.selectSaleAttrValuesBySpu(spuId);

        // 创建一个 Map 集合，存放最终整理好的数据
        Map<String, Object> finalDataMap = new HashMap<>();

        // 遍历原始数据 List 集合
        for (Map<String, Object> originalMap : originalDataList) {
            String valueIds = (String) originalMap.get("value_ids");
            Object skuId = originalMap.get("sku_id");

            // 存入最终结果 Map
            finalDataMap.put(valueIds, skuId);
        }

        return finalDataMap;
    }

    @Override
    @GmallCache(prefix = "portal:category")
    public List<JSONObject> getBaseCategoryList() {

        List<JSONObject> jsonObjectList = new ArrayList<>();

        // 1、先通过分类数据的视图，查询全部数据
        List<BaseCategoryView> allCategoryList =
                baseCategoryViewMapper.selectList(null);

        // 2、对上面查询到的 List 集合数据进行分组：根据一级分类分组
        Map<Long, List<BaseCategoryView>> category1GroupMap =
                allCategoryList.stream().collect(Collectors.groupingBy((BaseCategoryView categoryView) -> {

            // 这里返回的是分组的依据
            return categoryView.getCategory1Id();
        }));

        // 3、把一级分类数据从分组得到的 Map 集合中解析出来
        // [1]遍历分组得到的 Map
        Set<Map.Entry<Long, List<BaseCategoryView>>> category1GroupEntrySet =
                category1GroupMap.entrySet();

        // 声明 index 变量，初始值为 1
        int index = 1;

        for (Map.Entry<Long, List<BaseCategoryView>> category1GroupEntry : category1GroupEntrySet) {
            Long category1Id = category1GroupEntry.getKey();
            List<BaseCategoryView> category1List = category1GroupEntry.getValue();

            // [2]读取封装 JSON 数据所需要的数据
            // 由于分组之后，遍历得到的 category1List 中保存的每一个对象，都是一级分类数据对象
            // 所以取任何一个有效的下标都可以得到一级分类对象
            String category1Name = category1List.get(0).getCategory1Name();

            JSONObject category1JSONObj = new JSONObject();
            category1JSONObj.put("index", index);
            category1JSONObj.put("categoryId", category1Id);
            category1JSONObj.put("categoryName", category1Name);

            // 创建集合，用来存放一级分类的子节点：二级分类
            List<JSONObject> childOfCategory1 = new ArrayList<>();

            // 为了填充 childOfCategory1，我们需要对 category1List 进行分组
            Map<Long, List<BaseCategoryView>> category2GroupMap =
                    category1List
                            .stream()
                            .collect(Collectors.groupingBy(BaseCategoryView::getCategory2Id));

            // 为了解析二级分类分组得到的 category2GroupMap，需要对 category2GroupMap 进行遍历
            Set<Map.Entry<Long, List<BaseCategoryView>>> category2GroupEntrySet = category2GroupMap.entrySet();

            for (Map.Entry<Long, List<BaseCategoryView>> category2GroupEntry : category2GroupEntrySet) {

                Long category2Id = category2GroupEntry.getKey();
                List<BaseCategoryView> category2List = category2GroupEntry.getValue();

                JSONObject category2JSONObj = new JSONObject();
                // 读取二级分类数据
                category2JSONObj.put("categoryId", category2Id);
                category2JSONObj.put("categoryName", category2List.get(0).getCategory2Name());

                List<JSONObject> childOfCategory2 = new ArrayList<>();

                // 三级分类数据不重复，所以不需要分组，直接遍历 category2List 集合
                for (BaseCategoryView category : category2List) {
                    JSONObject category3JSONObj = new JSONObject();
                    category3JSONObj.put("categoryId", category.getCategory3Id());
                    category3JSONObj.put("categoryName", category.getCategory3Name());

                    // 把填充好的三级分类 category3JSONObj 对象存入 childOfCategory2 集合
                    childOfCategory2.add(category3JSONObj);
                }

                category2JSONObj.put("categoryChild", childOfCategory2);

                // 把填充好的二级分类 category2JSONObj 存入
                childOfCategory1.add(category2JSONObj);
            }

            category1JSONObj.put("categoryChild", childOfCategory1);

            // 对 index 数据执行 +1 操作
            index++;

            // 一级分类数据存入最终集合
            jsonObjectList.add(category1JSONObj);
        }

        return jsonObjectList;
    }

    @Override
    public List<BaseAttrInfo> getBaseAttrInfoListBySkuId(Long skuId) {

        return baseAttrInfoMapper.selectBaseAttrInfoListBySkuId(skuId);
    }
}
